--[[
    DragonBones Node Warper
    Create By Will
--]]

local Armature =  class("Armature",function(node)return node end)

local SoundLabelConfig

--if not db.CCArmatureDisplay.setUpdateInterval then
--    db.CCArmatureDisplay.setUpdateInterval = function(f)
--    end
--end

local Display_getBonePositionFunc = db.CCArmatureDisplay.getBonePosition
local Display_getBoneWorldPositionFunc = db.CCArmatureDisplay.getBoneWorldPosition
local Display_getArmature = db.CCArmatureDisplay.getArmature
local Display_getAnimation = db.CCArmatureDisplay.getAnimation
local Display_getSlotFunc = db.CCArmatureDisplay.getSlot
local Display_getChildArmatureDisplay = db.CCArmatureDisplay.getChildArmatureDisplay

local Armature_getBoneFunc = db.Armature.getBone


local Animation_getLastAnimationNameFunc = db.Animation.getLastAnimationName
local Animation_isPlayingFunc = db.Animation.isPlaying


Armature.getAniDuration = db.CCArmatureDisplay.getAnimationDuration

function Armature.create(params)
    local node ,skeletonKey ,textureKey = display.newArmature(params)
    if node then
        local autoAudio = params.autoAudio or false
        local armature = Armature.new(node)
        armature.skeletonKey = skeletonKey
        armature.textureKey = textureKey
        armature:setAutoPlaySound(autoAudio)
        return armature
    else
        return nil
    end
end

function Armature:ctor()
    self.defaultColor = cc.c3b(255,255,255)

    self.autoPlaySound = false
    self.autoPlayParticle = true
    self.aniPaused = false

    self:registerEventHandler(handler(self,self.handleAnimationEvent))

    if not SoundLabelConfig then
        SoundLabelConfig = app:loadResScript("scripts.config.soundlabel")
    end

    --[[
    local boundingBox = self:getBoundingBox()
    local drawNode = cc.DrawNode:create()
    self:addChild(drawNode)
    drawNode:drawRect(cc.p(boundingBox.x,boundingBox.y),cc.p(boundingBox.width,boundingBox.height),cc.c4f(1,1,0,1))
    ]]
end


--function Armature:getAnimation()
--    assert(Display_getArmature(self))
--    return getmetatable(self).getAnimation(self)
--end

function Armature:setAutoPlaySound(b)
    self.autoPlaySound = b
end

function Armature:setVolume(v)
    self._volume = v
end

function Armature:setDefaultColor(c)
    self.defaultColor = c
end

function Armature:getBoundingHeight()
    local armature = Display_getArmature(self)
    return armature:getBoundingHeight()
end

function Armature:hasBone(boneName)
    local armature = Display_getArmature(self)
    local bone = Armature_getBoneFunc(armature,boneName)
    return bone~=nil
end

function Armature:getBonePos(boneName)
    return Display_getBoneWorldPositionFunc(self,boneName)
end

function Armature:getBoneLocalPos(boneName)
    return Display_getBonePositionFunc(self,boneName)
end

function Armature:getSlotArmature(slotName)
    local slot = Display_getSlotFunc(self,slotName)
    local armature = nil
    if slot then
        armature = slot:getChildArmature()
    end
    return armature
end

function Armature:getSlotDisplay(slotName)
    return Display_getChildArmatureDisplay(self,slotName)
end

function Armature:setBlendMode(mode)
    self:forceBlendMode(mode or 0)
end

function Armature:applyShaderWithName(name)
    if cc.isAlive(self) then
        self:applyShader(name or "")
        self.curShaderName = name
    end
end

function Armature:getCurShaderName()
    return self.curShaderName
end

function Armature:getAnimationList()
    if cc.isDead(Display_getArmature(self)) then
        printError("===============> Armature:getAnimationList() fail! Armature is nil!")
        return {}
    end
    local animation = Display_getAnimation(self)
    return animation:getAnimationNames()
end

function Armature:hasAnimation(name)
    if cc.isDead(Display_getArmature(self)) then
        printError("===============> Armature:hasAnimation(name) fail! Armature is nil!")
        return false
    end
    local animation = Display_getAnimation(self)
    return animation:hasAnimation(name)
end

function Armature:isPlaying(aniName)
    if cc.isDead(Display_getArmature(self)) then
        printError("===============> Armature:isPlaying(aniName) fail! Armature is nil!")
        return false
    end
    local animation = Display_getAnimation(self)
    if aniName then
        local lastAniName = Animation_getLastAnimationNameFunc(animation)
        return lastAniName==aniName
    else
        return  Animation_isPlayingFunc(animation)
    end
end


function Armature:gotoAndPlay(...)
    if cc.isDead(Display_getArmature(self)) then
        printError("===============> Armature:gotoAndPlay(...) fail! Armature is nil!")
        return
    end
    local animation = Display_getAnimation(self)
    animation:gotoAndPlayByProgress(...)
end

function Armature:stop()
    if cc.isDead(Display_getArmature(self)) then
        printError("===============> Armature:stop() fail! Armature is nil!")
        return
    end
    local animation = Display_getAnimation(self)
    animation:stop("")
end

function Armature:pauseAni()
    if not self.aniPaused then
        self.aniPaused = true
        if cc.isDead(Display_getArmature(self)) then
            printError("===============> Armature:pauseAni() fail! Armature is nil!")
            return
        end
        local animation = Display_getAnimation(self)
        animation:stop("")
    end
end

function Armature:isPauseAni()
    return self.aniPaused
end

function Armature:resumeAni()
    if self.aniPaused then
        self.aniPaused = false
        self:play()
    end
end

function Armature:setTimeScale(...)
    if cc.isDead(Display_getArmature(self)) then
        printError("===============> Armature:setTimeScale(...) fail! Armature is nil!")
        return
    end
    local animation = Display_getAnimation(self)
    animation:setTimeScale(...)
end

--[[
{
name = "name" --动画名
next = "" --下个动画
fadeInTime = 0.2 --过度时间
duration = -1 --播放时间
playTimes = -1 --播放次数
startCallback = cb 
completeCallback = cb --完成回调
loopCompleteCallback = cb --循环完成回调
}
--]]
function Armature:playAni(params)
    if cc.isDead(Display_getArmature(self)) then
        print("===============> Armature:playAni(params) fail! Armature is nil!")
        dump(params, nil, 10)
        return false
    end
    if self.aniPaused then return false end

    local name = params.name
    local playTimes = params.playTimes or -1

    self.nextAni = params.next

    self._completedCallback = params.completeCallback
    self._loopCompletedCallback = params.loopCompleteCallback
    self._startCallback = params.startCallback
    
    local animation = Display_getAnimation(self)
    if not animation:hasAnimation(name) then
        if self._startCallback then
            self._startCallback(self)
        end
        if self._completedCallback then
            self._completedCallback(self)
        end
        --printLog(self:getArmature():getName(),"animation not find ["..name.."]")
        return false
    end

    local fadeInTime = params.fadeInTime
    if type(fadeInTime)=="number" and fadeInTime>0 then
        animation:fadeIn(name,fadeInTime,playTimes)
    else
        animation:play(name,playTimes)
    end
    return true
end

function Armature:play(name,playtimes,completeCallback,loopCompleteCallback)
    if self.aniPaused then return false end
    if cc.isDead(Display_getArmature(self)) then
        printError("===============> Armature:play(name,playtimes,completeCallback,loopCompleteCallback) fail! Armature is nil!")
        return
    end

    self._completedCallback = completeCallback
    self._loopCompletedCallback = loopCompleteCallback
    local animation = Display_getAnimation(self)

    if not animation:hasAnimation(name) then
        if self._completedCallback then
            self._completedCallback(self)
        end
        return false
    else
        animation:play(name or "",playtimes or -1)
    end
    return true
end

-- 播放默认动作，第一个动作 (有问题，隐藏一次之后，再次播放播不出来)
function Armature:playDefault(playtimes,completeCallback,loopCompleteCallback)
    if self.aniPaused then return false end
    if cc.isDead(Display_getArmature(self)) then
        printError("===============> playDefault(playtimes,completeCallback,loopCompleteCallback) fail! Armature is nil!")
        return
    end
    self._completedCallback = completeCallback
    self._loopCompletedCallback = loopCompleteCallback
    local animation = Display_getAnimation(self)
    animation:play("",playtimes or -1)
    return true
end

function Armature:fadeIn(name,fadeInTime,playtimes,completeCallback,loopCompleteCallback)
    if cc.isDead(Display_getArmature(self)) then
        printError("===============> fadeIn(name,fadeInTime,playtimes,completeCallback,loopCompleteCallback) fail! Armature is nil!")
        return
    end
    self._completedCallback = completeCallback
    self._loopCompletedCallback = loopCompleteCallback
    local animation = Display_getAnimation(self)

    if not animation:hasAnimation(name) then
        if self._completedCallback then
            self._completedCallback(self)
        end
    else
        animation:fadeIn(name or "",fadeInTime,playtimes or -1)
    end
end


function Armature:handleAnimationEvent(type,name)
    if type == "frameEvent" then
        if self._frameEventCallback then
            self._frameEventCallback(self,name)
        end
    elseif type == "soundEvent" then
        if self.autoPlaySound == true and self:isVisible() and SoundLabelConfig then
            local effectId = SoundLabelConfig[name]
            local audioID = AM.playSoundById(effectId)
            if self._volume and audioID then
                AM.setVolume(audioID,self._volume)
            end
        end
    elseif type=="particleEvent" then
        if self.autoPlayParticle then
            local splitArray = string.split(name,"_")
            local bone, parFile = splitArray[2],splitArray[3]
            local particleSys

            if bone == "none" then
                bone = nil
            end

            if parFile then
                local parPath = "armatures/effect/"..parFile..".plist"
                if cc.FileUtils:getInstance():isFileExist(parPath) then
                    particleSys = cc.ParticleSystemQuad:create(parPath)
                else
                    print("===>missing Particles file "..parPath)
                end
            end
            
            if particleSys then
                self:addChild(particleSys)
                if bone then
                    local localPosX,localPosY = self:getBoneLocalPos(bone)
                    particleSys:setPosition(localPosX,localPosY)
                else
                    particleSys:setPosition(0,0)
                end
            end
            --only create particle once
            self.autoPlayParticle = false
        end
    else
        self:handleMovementEvent(type,name)
    end
end

function Armature:handleMovementEvent(name,movementId)
    if "complete" == name then
        if self._completedCallback then
            self._completedCallback(self,movementId)
            self._completedCallback=nil
        end

        if self.nextAni then
            self:play(self.nextAni)
            self.nextAni = nil
        end
    elseif "loopComplete" == name then
        if self._loopCompletedCallback then
            self._loopCompletedCallback(self,movementId)
        end
    elseif "start" == name then
        if self._startCallback then
            self._startCallback(self,movementId)
        end
    end
end

function Armature:clearNextAni()
    self.nextAni = nil
end

function Armature:clearCompletedCallBack()
    self._completedCallback = nil
end

function Armature:getLastAnimationName()
    if cc.isDead(Display_getArmature(self)) then
        printError("===============> getLastAnimationName() fail! Armature is nil!")
        return ""
    end
    local name = ""
    local animation = Display_getAnimation(self)
    if animation then
        name = Animation_getLastAnimationNameFunc(animation)
    end
    return name
end

function Armature:onFrameEvent(cb)
    self._frameEventCallback = cb
end

return Armature